快速了解 TensorFlow 基础 (四) 基础运算

标量的运算

实数的四则运算加减乘除, 整除, 取余, 幂运算

TensorFlow 实现

加减乘除: tf.math.add(a,b) $+$, tf.math.subtract(a,b) $-$, tf.math.multiply(a,b) $\times$, tf.math.divide(a,b) $\div$

整除: $//$

取余: tf.math.mod(a,b) $%$

幂运算: tf.math.pow(x, a) $**$ $x^a$ 平方: tf.square(x)

开方: tf.math.pow(x, 1/a) $**$ $\sqrt[a]x$ 平方根: tf.sqrt(x)

指数运算: tf.math.pow(a, x) $**$ $a^x$ 自然指数 $e^x$ tf.exp(x)

对数运算: 自然对数: $log_e(x)$ tf.math.log(x) 其他对数: $log_a(x)=\frac{log_e(x)}{log_e(a)}$

正负数符号: tf.math.sign(a)

绝对值: tf.math.abs(a)

倒数: tf.math.inv(a)

向量的运算

向量与标量乘法

除法相当于乘以倒数, 向量方向不变, 扩大/缩小距离.

$$
k\begin{bmatrix}x_1\\x_2\\x_3\end{bmatrix}=
\begin{bmatrix}kx_1\\kx_2\\kx_3\end{bmatrix}
$$

向量与向量的点乘

结果是标量, 用于描述两个向量的相似度.

$$
\begin{bmatrix}x_1\\x_2\\x_3\end{bmatrix}
\cdot
\begin{bmatrix}y_1\\y_2\\y_3\end{bmatrix}
= x_1y_1+x_2y_2+x_3y_3
$$

向量与向量的叉乘

$$
\begin{bmatrix}x_1\\x_2\\x_3\end{bmatrix}
\times
\begin{bmatrix}y_1\\y_2\\y_3\end{bmatrix}
=
\begin{bmatrix}x_2y_3-x_3y_2\\x_3y_1-x_1y_3\\x_1y_2-x_2y_1\end{bmatrix}
$$

参考: 向量运算

矩阵的运算

矩阵与标量乘法

$$
kM
=
k\begin{bmatrix}
m_{11} & m_{12} & m_{13} \\
m_{21} & m_{22} & m_{23} \\
m_{31} & m_{32} & m_{33}
\end{bmatrix}
=
\begin{bmatrix}
km_{11} & km_{12} & km_{13} \\
km_{21} & km_{22} & km_{23} \\
km_{31} & km_{32} & km_{33}
\end{bmatrix}
$$

矩阵与矩阵乘法

rxn 矩阵 A 与一个 nxc 矩阵 B 相乘,则得到一个 rxc 矩阵 C.

$$
AB =
\begin{bmatrix}
a_{11} & a_{12} \\
a_{21} & a_{22} \\
a_{31} & a_{32}
\end{bmatrix}
\begin{bmatrix}
b_{11} & b_{12} & b_{13} & b_{14} \\
b_{21} & b_{22} & b_{23} & b_{24}
\end{bmatrix}
\\ =
\begin{bmatrix}
a_{11}b_{11} + a_{12}b_{21} & a_{11}b_{12} + a_{12}b_{22} & a_{11}b_{13} + a_{12}b_{23} & a_{11}b_{14} + a_{12}b_{24} \\
a_{21}b_{11} + a_{22}b_{21} & a_{21}b_{12} + a_{22}b_{22} & a_{21}b_{13} + a_{22}b_{23} & a_{21}b_{14} + a_{22}b_{24} \\
a_{31}b_{11} + a_{32}b_{21} & a_{31}b_{12} + a_{32}b_{22} & a_{31}b_{13} + a_{32}b_{23} & a_{31}b_{14} + a_{32}b_{24}
\end{bmatrix}
\\ =
\begin{bmatrix}
c_{11} & c_{12} & c_{13} & c_{14} \\
c_{21} & c_{22} & c_{23} & c_{24} \\
c_{31} & c_{32} & c_{33} & c_{34}
\end{bmatrix}
= C
$$

每个元素的值算法

$$c_{ij}=\sum_{k=1}^{n}a_{ik}b_{kj}$$

矩阵与向量乘法

向量是特殊的矩阵, 乘法符合矩阵与矩阵的乘法.

为了保持 $A_{r,n} \times B_{n,c}$ 相乘的关系, 行向量需要左乘矩阵, 列向量需要右乘矩阵.

行向量 * 矩阵

$$
行向量 \times 矩阵
=
\begin{bmatrix}
a_{11} & a_{12}
\end{bmatrix}
\begin{bmatrix}
b_{11} & b_{12} & b_{13} \\
b_{21} & b_{22} & b_{23}
\end{bmatrix}
=
\begin{bmatrix}
a_{11}b_{11} + a_{12}b_{21} & a_{11}b_{12} + a_{12}b_{22} & a_{11}b_{13} + a_{12}b_{23}
\end{bmatrix}
$$

矩阵 * 行向量

$$
矩阵 \times 行向量
=
\begin{bmatrix}
a_{11} & a_{12} \\
a_{21} & a_{22} \\
a_{31} & a_{32}
\end{bmatrix}
\begin{bmatrix}
b_{11} \\
b_{21}
\end{bmatrix}
=
\begin{bmatrix}
a_{11}b_{11} + a_{12}b_{21} \\
a_{21}b_{11} + a_{22}b_{21} \\
a_{31}b_{11} + a_{32}b_{21}
\end{bmatrix}
$$

横向量与列向量乘法

横向量与列向量均为特殊的矩阵, 横向量与列向量乘法可以看做是矩阵乘法.

行向量 * 列向量

$$
行向量 \times 矩阵
=
\begin{bmatrix}
a_{11} & a_{12}
\end{bmatrix}
\begin{bmatrix}
b_{11} \\
b_{21}
\end{bmatrix}
=
\begin{bmatrix}
a_{11}b_{11} + a_{12}b_{21}
\end{bmatrix}
$$

参考: 矩阵运算

使用 Numpy 和 TensorFlow 对矩阵进行乘法运算

点乘(“*“) — 各个矩阵对应元素做乘法

$w$ 为 $m \times 1$ 矩阵, $X$ 为 $m \times n$ 矩阵

$$
Y = wX =
\begin{bmatrix}
w_11 \\
w_21
\end{bmatrix}
\begin{bmatrix}
x_11 & x_12 & x_13 \\
x_21 & x_22 & x_23
\end{bmatrix}
=
\begin{bmatrix}
w_11x_11 & w_11x_12 & w_11x_13 \\
w_21x_21 & w_21x_22 & w_21x_23
\end{bmatrix}
$$

$w$ 为 $m \times n$ 矩阵, $X$ 为 $m \times n$ 矩阵

$$
Y = wX =
\begin{bmatrix}
w_11 & w_12 & w_13\\
w_21 & w_22 & w_23
\end{bmatrix}
\begin{bmatrix}
x_11 & x_12 & x_13 \\
x_21 & x_22 & x_23
\end{bmatrix}
=
\begin{bmatrix}
w_11x_11 & w_12x_12 & w_13x_13 \\
w_21x_21 & w_22x_22 & w_23x_23
\end{bmatrix}
$$

$w$ 的列数只能为 1 或 与 x 的列数相等(即 n), $w$ 的行数与 x 的行数相等, 才能进行乘法运算.

矩阵乘 — 按照矩阵乘法规则做运算

$$
Y = wX =
\begin{bmatrix}
w_{11} & w_{12} \\
w_{21} & w_{22} \\
w_{31} & w_{32}
\end{bmatrix}
\begin{bmatrix}
x_{11} & x_{12} & x_{13} & x_{14} \\
x_{21} & x_{22} & x_{23} & x_{24}
\end{bmatrix}
\\ =
\begin{bmatrix}
w_{11}x_{11} + w_{12}x_{21} & w_{11}x_{12} + w_{12}x_{22} & w_{11}x_{13} + w_{12}x_{23} & w_{11}x_{14} + w_{12}x_{24} \\
w_{21}x_{11} + w_{22}x_{21} & w_{21}x_{12} + w_{22}x_{22} & w_{21}x_{13} + w_{22}x_{23} & w_{21}x_{14} + w_{22}x_{24} \\
w_{31}x_{11} + w_{32}x_{21} & w_{31}x_{12} + w_{32}x_{22} & w_{31}x_{13} + w_{32}x_{23} & w_{31}x_{14} + w_{32}x_{24}
\end{bmatrix}
$$

TensorFlow 高阶矩阵相乘

也就是张量 𝑨𝑩 的维度数大于 2 时, 会选择 𝑨𝑩 的最后两个维度进行矩阵相乘, 前面的所有维度视作 Batch 维度.

Batch 维度必须相同, 𝑨 的倒数第一个维度长度(列)和 𝑩 的倒数第二个维度长度(行)必须相等.

1
2
3
4
5
6
7
8
9
10
# 前几位相同, a 倒数第一位 与 b 倒数第二位相同
a = tf.random.normal([4,3,28,32])
b = tf.random.normal([4,3,32,2])
# c.shape = [4,3,28,2]

# 前几位缺位, 倒数第一位 与 b 倒数第二位相同
a = tf.random.normal([4,3,28,32])
b = tf.random.normal([32,2])
# b = b.broadcast_to([4,3,32,2])
# c.shape = [4,3,28,2]

Numpy 的写法

点乘

1
2
3
4
5
6
7
8
9
10
import numpy as np

# w: [2 x 1]
# x: [2 x 5]

w = np.array([[0.4], [1.2]])
x = np.array([range(1,6), range(5,10)])

# 点乘法
y = w * x

矩阵乘

1
2
3
4
5
6
7
8
9
10
import numpy as np

# w: [2 x 1]
# x: [2 x 5]

w = np.array([[0.4, 1.2]])
x = np.array([range(1,6), range(5,10)])

# 矩阵乘法
y = np.dot(w,x)

TensorFlow 的写法

点乘法

1
2
3
4
5
6
7
8
9
10
import tensorflow as tf

# w.shape: [2, 1]
# x.shape: [2, 5]

w = tf.constant([[0.4], [1.2]], dtype=tf.float32)
x = tf.constant([range(1,6), range(5,10)], dtype=tf.float32)

# 点乘法, 等同于 y = tf.multiply(w, x), y.shape: [2, 5]
y = w * x

矩阵乘法

1
2
3
4
5
6
7
8
9
10
import tensorflow as tf

# w.shape: [1, 2]
# x.shape: [2, 5]

w = tf.constant([[0.4, 1.2]], dtype=tf.float32)
x = tf.constant([range(1,6), range(5,10)], dtype=tf.float32)

# 矩阵乘法, 等同于 y = tf.matmul(w, x), y.shape: [1, 5]
y = w @ x

参考: Python 之 numpy 和 tensorflow 中的各种乘法(点乘和矩阵乘)

维度变换

tf 基本的维度变换操作函数包含了 reshape 改变视图 , expand_dims 插入新维度 , squeeze 删除维度, transpose 交换维度, tile 复制数据, broadcast_to 形状扩张等, 其中 broadcast_to 往往可以自动进行.

$𝒀=𝑿@𝑾+𝒃$ 在计算过程中, $𝑿@𝑾$ 是 $m \times n$ 维张量, $𝒃$ 是 $n$ 维向量, 无法直接进行 + 运算.

shape = [1,n] 的 bias 偏置 $𝒃 = \begin{bmatrix} b_1 & b_2 & b_3 \end{bmatrix}$ 的样本数复制扩展到 shape = [m,n] $𝒃 = \begin{bmatrix} b_1 & b_2 & b_3 \ b_1 & b_2 & b_3 \end{bmatrix}$

$$
𝒀=𝑿@𝑾+𝒃 \\
=
𝑿@𝑾
+
\begin{bmatrix} b_1 & b_2 & b_3 \end{bmatrix} \\
=
𝑿@𝑾
+
\begin{bmatrix} b_1 & b_2 & b_3 \ b_1 & b_2 & b_3 \end{bmatrix} \\
=
\begin{bmatrix} x_{11} & x_{12} & x_{13} \ x_{21} & x_{22} & x_{23} \ \end{bmatrix}
+
\begin{bmatrix} b_1 & b_2 & b_3 \ b_1 & b_2 & b_3 \end{bmatrix} \\
=
\begin{bmatrix} x_{11}+b_1 & x_{12}+b_2 & x_{13}+b_3 \ x_{21}+b_1 & x_{22}+b_2 & x_{23}+b_3 \ \end{bmatrix}
$$

通过 维度变换 满足了数学上矩阵相加需要 shape 一致的条件,又达到了给每个输入样本的输出节点共享偏置向量的逻辑.

视图 与 reshape 改变视图

在介绍改变视图 reshape 操作之前,我们先来认识一下张量的存储(Storage)和视图 (View)的概念。张量的视图就是我们理解张量的方式,比如 shape 为[2,4,4,3]的张量 𝑨,我 们从逻辑上可以理解为 2 张图片,每张图片 4 行 4 列,每个位置有 RGB 3 个通道的数据; 张量的存储体现在张量在内存上保存为一段连续的内存区域,对于同样的存储,我们可以 有不同的理解方式,比如上述张量 𝑨,我们可以在不改变张量的存储下,将张量 𝑨 理解为 2 个样本,每个样本的特征为长度 48 的向量。同一个存储,从不同的角度观察数据,可以产 生不同的视图,这就是存储与视图的关系。视图的产生是非常灵活的,但需要保证是合理。

在存储数据时,内存并不支持这个维度层级概念,只能以平铺方式按序写入内存,因此这 种层级关系需要人为管理. 为了方便表达,我们把张量 shape 列表中相对靠左侧的维度叫作大维度,shape 列表中相对靠右侧的维度叫作小维度.

1
2
3
# 模拟生成张量, 将存储数据以 shape [2,4,4,3] 视图展示
x = tf.range(96)
x = tf.reshape(x, [2,4,4,3])

数据的顺序不变, [b, h, w, c] 可以转化成 [b, hw, c], [b, hwc] 都可以说得通. 特殊的是, -1 表示前面确定了之后, 根据张量元素不变法则自动推导.

expend_dims 增加维度与 squeeze 删除维度

[h, w] 在最后增加一个维度 [h, w, 1], 存储不变, 表示某个通道, 视图显示变了.
[h, w] 在最前增加一个维度 [1, h, w], 存储不变, 表示某张图片, 视图显示变了.

tf.expand_dims(x, axis), 增加维度, 其中 axis >=0 表示在指定的 axis 轴前增加维度, axis < 0 表示从右往左数第几个位置.

与增加维度一样,删除维度只能删除长度为 1 的维 度,也不会改变张量的存储.

tf.squeeze(x, axis) 删除 axis 位置的维度.

循环产出的时候,尽量从右向左判断删除,防止从左到右删除的时候,右面的维度索引变化

transpose 交换维度

改变视图、增删维度都不会影响张量的存储.

交换维度会影响数据的存储. 例如 [b, h, w, c][b, c, h, w] 的维度交换, 只提供 reshape 得到的数据是不合法的.

tf.transpose(x, new_order) 对原有维度进行交换. new_order 是原有顺序 0,1,2… 的重排 tf.transpose(x, [0,3,1,2])

tile 复制数据

使用 tf.tile(x,multiples=[times,...]) 在某一个维度上进行数据的复制, times 表示结果是当前的几倍, 1 表示不复制. 例如 $shape [2,4] \times multiples [2,3] = shape [4,12]$ 第一维度是 2 倍, 第二位的是 3 倍.

tf.tile 会创建一个新的张量来保存复制后的张量,由于复制操作涉及大 量数据的读写 IO 运算,计算代价相对较高.

broadcasting 自动扩展机制

神经网络中不同 shape 之间的张量运算操作十分频繁, 使用 broadcasting 可以减少 tile 对数据的复制.

tf.broadcast_to(x, shape) 在一定的已知情况, 可以替代 tile 进行自动的数据复制. 复制机制为张量靠右对齐, 空维度以维度 1 补齐. 从右往左依次判断是否两个向量是否具有普适性, 维度为 1 或者维度相同表示具有普适性.

没有普适性无法使用 broadcasting 机制.

Donate - Support to make this site better.
捐助 - 支持我让我做得更好.